﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Xml;
using Send2Sharepoint.Common;
using Send2Sharepoint.Copy;

namespace Send2Sharepoint.Forms
{
    public partial class IndexDocument : Form
    {
        private const int LabelXPosition = 20;
        private const int FieldXPosition = 160;
        private const int StartYPosition = 32;
        private readonly string _userName = Globals.UserName;
        private readonly string _password = Globals.Password;
        private readonly string _documentLibraryName = Globals.DocumentLibrary;
        private readonly List<KeyValuePair<string, KeyValuePair<double, double>>> _minMaxValues = new List<KeyValuePair<string, KeyValuePair<double, double>>>();
        private readonly WorkItem _workItem;

        public IndexDocument()
        {
            InitializeComponent();
        }

        public IndexDocument(WorkItem workItem) : this()
        {
            _workItem = workItem;
        }

        private void IndexDocument_Load(object sender, EventArgs e)
        {
            var repository = new Repository.Repository(_userName, _password,Globals.SharepointSiteUrl);
            var elements = repository.GetColumnsMetaData(_documentLibraryName);
            var yPosition = StartYPosition;
            var inputControlFactoryImplementation = new InputControlFactoryImplementation();
            foreach (var element in elements)
            {
                var labelField = inputControlFactoryImplementation.MakeInputControl(element);
                AddValidationEvents(element, labelField);
                PositionControl(labelField, yPosition);
                yPosition += labelField.Field.Height;
                AddControl(labelField);
            }
            errorProvider.ContainerControl = this;
            MoveButtonsAndResizeForm(yPosition);
        }

        private void MoveButtonsAndResizeForm(int yPosition)
        {
            yPosition += 27;
            btnSend.Location = new Point(LabelXPosition, yPosition);
            btnCancel.Location = new Point(btnSend.Width + 30,yPosition);
            progressBar.Location = new Point(btnCancel.Width + btnSend.Width + 40,yPosition);
            yPosition += 85;
            Height = yPosition;
            FormBorderStyle = FormBorderStyle.FixedSingle;
        }

        private IEnumerable<FieldInformation> GetIndexInformation()
        {
            var indexInformation = new List<FieldInformation>();
            foreach (Control control in Controls)
            {
                if (control.Name.StartsWith("control"))
                {
                    var position = control.Name.IndexOf('_');
                    FieldInformation fieldInfo = null;
                    switch (control.Name.Substring(7,position-7))
                    {
                        case "YesNo":
                            fieldInfo = new FieldInformation
                            {
                                Value = ((CheckBox)control).Checked.ToString(),
                                DisplayName = control.Name.Substring(position + 1),
                                Type = FieldType.Boolean,
                                InternalName = control.Name.Substring(position + 1)
                            };
                            break;
                        case "DtPicker":
                            fieldInfo = new FieldInformation
                            {
                                Value = String.Format("{0:MM/dd/yyyy HH:mm:ss}", ((DateTimePicker)control).Value),
                                DisplayName = control.Name.Substring(position + 1),
                                Type = FieldType.DateTime,
                                InternalName = control.Name.Substring(position + 1)
                            };
                            break;
                        case "Group":
                            var type = control.Name.Substring(position+1);
                            string controlName;
                            switch(type)
                            {
                                case "Radio":
                                    var selectedControl = (control.Controls.Cast<Control>())
                                                            .Where(c => ((RadioButton) c).Checked)
                                                            .Single();
                                    controlName = selectedControl.Name.Substring(0,
                                                                                 selectedControl.Name.IndexOf("_"));
                                    fieldInfo = new FieldInformation
                                    {
                                        Value = selectedControl.Text,
                                        DisplayName = controlName,
                                        Type = FieldType.Choice,
                                        InternalName = controlName
                                    };
                                    break;
                                case "Check":
                                    var selectedControls = (control.Controls.Cast<Control>())
                                                            .Where(c => ((CheckBox)c)
                                                            .Checked);
                                    controlName = selectedControls.First().Name.Substring(0,selectedControls.First().Name.IndexOf("_"));
                                    fieldInfo = new FieldInformation
                                    {
                                        Value = String.Join("#",selectedControls.Select(c => c.Text).ToArray()),
                                        DisplayName = controlName,
                                        Type = FieldType.MultiChoice,
                                        InternalName = controlName
                                    };
                                    break;
                            }
                            break;
                        case "Combo":
                            fieldInfo = new FieldInformation
                            {
                                Value = ((ComboBox)control).SelectedItem.ToString(),
                                DisplayName = control.Name.Substring(position + 1),
                                Type = FieldType.Choice,
                                InternalName = control.Name.Substring(position + 1)
                            };
                            break;
                        case "TxtArea":
                        case "TxtBox":
                            fieldInfo = new FieldInformation
                            {
                                Value = control.Text,
                                DisplayName = control.Name.Substring(position + 1),
                                Type = FieldType.Text,
                                InternalName = control.Name.Substring(position + 1)
                            };
                            break;
                    }
                    indexInformation.Add(fieldInfo);
                }
            }
            return indexInformation;
        }

        private void BtnSendClick(object sender, EventArgs e)
        {
            if (_workItem != null)
            {
                DisableAllControls();
                if (ValidateChildren())
                {
                    btnCancel.Enabled = true;
                    btnSend.Enabled = false;
                    Cursor = Cursors.WaitCursor;
                    _workItem.IndexInformation = GetIndexInformation();
                    backgroundWorker.RunWorkerAsync(_workItem);
                    MaximizeBox = false;
                }
                else
                {
                    EnableAllControls();
                }
            }
            else
            {
                MessageBox.Show("workitem is null");
                btnCancel.Enabled = true;
            }
        }

        private void DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                var worker = (BackgroundWorker)sender;
                var workItem = (WorkItem)e.Argument;
                workItem.Upload(worker, e);
            }
            catch (Exception ex)
            {
                Logging.WriteException(ex);
            }
        }

        private void AddControl(InputControl labelField)
        {
            Controls.Add(labelField.Label);
            Controls.Add(labelField.Field);
        }

        private static void PositionControl(InputControl labelField, int yPosition)
        {
            labelField.Label.Location = new Point(LabelXPosition, yPosition);
            labelField.Field.Location = new Point(FieldXPosition, yPosition);
        }

        #region Validation Events

        private void NumberValidating(object sender, CancelEventArgs e)
        {
            var control = (Control)sender;
            double value;
            e.Cancel = true;
            var controlName = control.Name.Substring(control.Name.IndexOf('_')+1);
            var min = (_minMaxValues.Find(v => (v.Key == controlName)).Value).Key;
            var max = (_minMaxValues.Find(v => (v.Key == controlName)).Value).Value;
            if (!Double.TryParse(Convert.ToString(control.Text), out value))
                errorProvider.SetError(control, "Number Required");
            else if (value < min || value > max)
                errorProvider.SetError(control, "Number must be in range " + min + " and " + max);
            else
                e.Cancel = false;
        }

        private void AddValidationEvents(XmlNode element, InputControl labelField)
        {
            var attributeCollection = element.Attributes;
            var name = attributeCollection["Name"].Value;
            var min = attributeCollection["Min"] != null ? double.Parse(attributeCollection["Min"].Value) : double.MinValue;
            var max = attributeCollection["Max"] != null ? double.Parse(attributeCollection["Max"].Value) : double.MaxValue;
            
            if (attributeCollection["Type"].Value == "Number")
            {
                if (attributeCollection["Percentage"] != null && attributeCollection["Percentage"].Value == "TRUE")
                {
                    min = min*100;
                    max = max*100;
                }

                labelField.Field.Validating += NumberValidating;
                labelField.Field.CausesValidation = true;
            }
            if (attributeCollection["Required"] != null && attributeCollection["Required"].Value == "TRUE")
            {
                labelField.Field.Validating += ControlRequiredValidating;
                labelField.Field.CausesValidation = true;
            }
            _minMaxValues.Add(new KeyValuePair<string, KeyValuePair<double, double>>(name, new KeyValuePair<double, double>(min, max)));
        }

        private void ControlRequiredValidating(object sender, CancelEventArgs e)
        {
            var control = (Control)sender;
            if (string.IsNullOrEmpty(control.Text))
            {
                errorProvider.SetError(control, "Required");
                e.Cancel = true;
            }
            else
                e.Cancel = false;
        }

        #endregion

        #region Enable/Disable Controls

        

        private void DisableAllControls()
        {
            foreach (Control c in Controls)
            {
                if (c.Name != "btnCancel")
                {
                    c.Enabled = false;
                }
            }
        }

        private void EnableAllControls()
        {
            foreach (Control c in Controls)
            {
                c.Enabled = true;
            }
        }

        #endregion

        private void WorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            progressBar.Value = 0;
            btnSend.Enabled = true;
            btnCancel.Enabled = true;
            EnableAllControls();
            MaximizeBox = true;
            Cursor = Cursors.Default;
        }

        private void ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar.Value = e.ProgressPercentage;
        }

    }
}